package com.beerandjesus.sportofkings.handicapper.app.brisnet.singlefile;

import com.beerandjesus.sportofkings.handicapper.app.CardAnalyzer;
import com.beerandjesus.sportofkings.handicapper.app.CardAnalyzerException;
import com.beerandjesus.sportofkings.handicapper.model.RaceAnalysisResultVO;
import com.beerandjesus.sportofkings.handicapper.model.CardVO;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.*;
import com.beerandjesus.sportofkings.handicapper.factory.brisnet.singlefile.RaceFactory;
import com.beerandjesus.sportofkings.handicapper.factory.brisnet.singlefile.HorseFactory;
import com.beerandjesus.sportofkings.handicapper.strategy.brisnet.singlefile.MaidenRaceAnalysisStrategy;
import com.beerandjesus.sportofkings.handicapper.strategy.brisnet.singlefile.NonMaidenRaceAnalysisStrategy;

import java.util.List;
import java.util.ArrayList;
import java.io.*;

import org.apache.commons.lang.StringUtils;

/**
 * A CardAnalyzer that analyzes a card in the form of a Brisnet past performances
 * data file in single file format.
 * <p/>
 * Date: May 25, 2012
 * Time: 5:34:26 PM
 */
public class CardAnalyzerImpl implements CardAnalyzer {

    private RaceFactory raceFactory;
    private HorseFactory horseFactory;
    private MaidenRaceAnalysisStrategy<HorseRace> maidenAnalysisStrategy;
    private NonMaidenRaceAnalysisStrategy<HorseRace> nonMaidenAnalysisStrategy;


    public List<RaceAnalysisResultVO> analyzeCard(CardVO card) throws CardAnalyzerException {
        if (card == null || !CardVOImpl.class.isAssignableFrom(card.getClass())) {
            throw new IllegalArgumentException("CardVO cannot be null, and must be an instance of " + CardVOImpl.class.getCanonicalName());
        }
        CardVOImpl c = (CardVOImpl) card;
        File file = new File(c.getFilePath());
        BufferedReader r;
        try {
            r = new BufferedReader(new FileReader(file));
        } catch (FileNotFoundException e) {
            throw new CardAnalyzerException("Past performances file not found", e);
        }
        String line;
        Integer currentRaceNumber = 0;
        Race currentRace = null;
        List<Horse> horses = new ArrayList<Horse>();
        List<RaceAnalysisResultVO> bvos = new ArrayList<RaceAnalysisResultVO>();
        try {
            while ((line = r.readLine()) != null) {
                Race race = getRaceFactory().getRace(line);
                Horse horse = getHorseFactory().getHorse(line);
                String raceNum = race.getRaceNumber();
                if (currentRace == null) {
                    // First race on the card
                    currentRace = race;
                    currentRaceNumber = new Integer(raceNum);
                    horses.add(horse);
                } else if (!StringUtils.isEmpty(raceNum) && !(new Integer(raceNum).equals(currentRaceNumber))) {
                    // New race. We need to analyze the last race now.
                    analyzeRace(currentRace, horses, bvos);
                    // Now set up the next race and add the first horse
                    currentRaceNumber = new Integer(raceNum);
                    currentRace = race;
                    horses.clear();
                    horses.add(horse);
                } else {
                    // Another horse for the current race
                    horses.add(horse);
                }
            }
            // Last race complete. Need to analyze it.
            analyzeRace(currentRace, horses, bvos);
        } catch (IOException e) {
            throw new CardAnalyzerException("Error analyzing past performances file", e);
        }

        return bvos;
    }

    private void analyzeRace(Race currentRace, List<Horse> horses, List<RaceAnalysisResultVO> bvos) {
        HorseRaceImpl hr = new HorseRaceImpl();
        hr.setRace(currentRace);
        hr.setHorses(new ArrayList<Horse>(horses));
        if (currentRace.getType().isMaiden()) {
            bvos.add(maidenAnalysisStrategy.analyze(hr));
        } else {
            bvos.add(nonMaidenAnalysisStrategy.analyze(hr));
        }
    }

    public RaceFactory getRaceFactory() {
        return raceFactory;
    }

    public void setRaceFactory(RaceFactory raceFactory) {
        this.raceFactory = raceFactory;
    }

    public HorseFactory getHorseFactory() {
        return horseFactory;
    }

    public void setHorseFactory(HorseFactory horseFactory) {
        this.horseFactory = horseFactory;
    }

    public MaidenRaceAnalysisStrategy getMaidenAnalysisStrategy() {
        return maidenAnalysisStrategy;
    }

    public void setMaidenAnalysisStrategy(MaidenRaceAnalysisStrategy<HorseRace> maidenAnalysisStrategy) {
        this.maidenAnalysisStrategy = maidenAnalysisStrategy;
    }

    public NonMaidenRaceAnalysisStrategy getNonMaidenAnalysisStrategy() {
        return nonMaidenAnalysisStrategy;
    }

    public void setNonMaidenAnalysisStrategy(NonMaidenRaceAnalysisStrategy<HorseRace> nonMaidenAnalysisStrategy) {
        this.nonMaidenAnalysisStrategy = nonMaidenAnalysisStrategy;
    }
}
